grammar plp2;


@header {
	import java.lang.String;
	import java.util.ArrayList;
}

@rulecatch {
	catch (RecognitionException e) {
		reportError(e);
		System.exit(1);
	}
}
@members {
	private TablaSimbolos tsimbolos = new TablaSimbolos(null,null);
	
	public void error5 (int fila, int columna, String cadena){
		emitErrorMessage("Error 5 (" + fila + "," + (columna+1) + "): '" + cadena + "' ya existe en este ambito");
System.exit(1);
	}
	
	public void error6 (int fila, int columna, String cadena){
		emitErrorMessage("Error 6 (" + fila + "," + (columna+1) + "): '" + cadena + "' no ha sido declarado");
System.exit(1);
	}
	
	public void error7 (int fila, int columna, String cadena){
		emitErrorMessage("Error 7 (" + fila + "," + (columna+1) + "): '" + cadena + "' no es una variable");
System.exit(1);
	}
	
	public void error8 (int fila, int columna, String cadena){
		emitErrorMessage("Error 8 (" + fila + "," + (columna+1) + "): '" + cadena + "' debe ser de tipo real");
System.exit(1);
	}


}


@lexer::members {
	
	public void emitErrorMessage(String mensaje)
	{
		System.err.println(mensaje);
		System.exit(1);
	}
	
}

	s returns [String salida]
		@init{	
			$salida = "";
		        String cad = "class TradC {\n\n";
       			String[] bicad = new String[2];
        		Simbolo s;
        		
		}:
		sp{
			cad+= $sp.salida;
			cad+= "\npublic static void main(String[] args){\n";
			s = tsimbolos.nuevoSimbolo("main", Simbolo.METODO, Simbolo.ES_MAIN);
		} MAIN PARI PARD bloque[s]{
			bicad = $bloque.salida;
			cad+= bicad[0];
			cad+= bicad[1];
			cad+= "\n}\n";
			
		}EOF{
			$salida = cad+"}\n";	
			if(AnalitzadorSintactic.pirulaSegura()){
				$salida = AnalitzadorSintactic.loSiento();
			}
		};
		
	sp returns [String salida]
		@init{
			$salida = "";	
		}:
		(funcion{
			$salida += $funcion.salida;		
					
		})*;
		
	funcion returns [String salida]
		@init{
			$salida="";
			String cad="public static ";
			String[] bicad = null;
			Simbolo s=null;
			String auxS;
			int auxInt;
		}:
		tipo[true]{
			cad+= $tipo.salida;			
		}
		ID{
			auxS = $ID.text;
			auxInt = $tipo.tipo;
			s = tsimbolos.nuevoSimbolo(auxS,Simbolo.METODO,auxInt);
			cad+= " " + $ID.text;
		}
		PARI
		PARD
		bloque[s]{
			bicad = $bloque.salida;
			cad += "(){\n\n";
			cad += bicad[0];
			cad += bicad[1];
			
		}{
			$salida = cad + "\n}\n";
		};
		
	tipo[boolean funcion] returns [String salida, int tipo]
		@init{
			$salida="";
			String cad="";
		}:
		INT{
			$tipo = Simbolo.ENTERO;
		  	if (funcion) {
                		cad += "int";
                		
            		} else {
                		cad += "Integer";
                		
                	}
                	$salida = cad;
            		
		}
		| DOUBLE {
			$tipo = Simbolo.REAL;
			if (funcion) {
                		cad += "double";
            		} else {
                		cad += "Double";
            		}	
            		$salida = cad;
            		
		}
		
		{
			
		
		};
		
	bloque[Simbolo s] returns [String[\] salida]
		@init{
			$salida = null;
		}:
		LLAVEI{
			tsimbolos = new TablaSimbolos(tsimbolos, s);
		}
		secinstr{
			
			$salida = $secinstr.salida;
	
					
		}
		LLAVED{
			tsimbolos = tsimbolos.pop();
		}
		;
		
	secinstr returns [String[\] salida]
		@init{
			$salida=null;
			String cad1 = "";
       			String bicad[] = new String[2];
        		bicad[0] = "";
        		bicad[1] = "";
			String cad="";
		}:
		(
		v{
			cad+= $v.salida;
			
		}
		|
		instr{
			bicad[0] += $instr.salida[0];
			bicad[1] += $instr.salida[1];
		})*
		{
			bicad[0] = cad + bicad[0];
			$salida = bicad;
		};
		
	v returns [String salida]
		@init{
			$salida="";
			String cad="";
		}:
		tipo[false]{
			cad+= $tipo.salida;
		
		}
		ID{
		        if (tsimbolos.existe($ID.text)) {
                		error5($ID.line,$ID.pos,$ID.text);
            		}
			tsimbolos.nuevoSimbolo($ID.text, Simbolo.VAR, $tipo.tipo);
		
			cad+= " " + tsimbolos.obtinNom($ID.text);
			
		}		
		PYC{
			$salida = cad + $PYC.text+"\n";
		}
		
		;
		
	instr returns [String[\] salida]
		@init{
			$salida=null;
			String[] bicad = new String[2];
			Simbolo sA = null;	
			boolean error8= false;
		
		}:
		ID{
			bicad[0]="";
			bicad[1]="";
			sA = tsimbolos.busca($ID.text);
			if (sA == null) {
                		error6($ID.line,$ID.pos,$ID.text);
            		} else if (sA.esMETODO()) {
                		error7($ID.line,$ID.pos,$ID.text);
            		}
            		bicad[1] += tsimbolos.obtinNom(sA.nombre);
            		
		}
		ASIG{
			bicad[1] += " = " ;
			
		}
		expr[sA]{
		
			
			bicad[1] += $expr.salida;
			error8 = $expr.error8;
			
		}
		PYC{
			//System.out.println(sA.tipo + " " + $expr.tipo);
			if(error8){
				error8($ID.line, $ID.pos, $ID.text);
			}
			bicad[1]+= $PYC.text;
			bicad[1]+="\n";
			$salida=bicad;
			
		}
		|
		bloque[null]{
		
			bicad=$bloque.salida;
			bicad[1]+="\n";
			$salida=bicad;
		}{
			
}
		;
		
	expr[Simbolo sA] returns [String salida, int tipo, boolean error8]
		@init{
			$salida="";
			String cad="";
			int tipoB=-1; 
			boolean sucedio = false;

			
					
		}:
		t1=term[sA,tipoB,true,sucedio,""]{
			tipoB = t1.tipo;
			cad += t1.salida;
			sucedio = t1.sucedio;
			$tipo = tipoB;
			$error8 = t1.error8;
		}
		(ADDOP{
			if(!sucedio){
			if(sA.tipo == Simbolo.ENTERO){
				cad = "new Integer("+cad;
			} else {
				cad = "new Double(" + cad;
			}}

			sucedio = true;
		}{
		
			//cad+= $ADDOP.text;
			tipoB = t1.tipo;
		} t2=term[sA,tipoB,false, sucedio,$ADDOP.text]{	
			if(tipoB == Simbolo.ENTERO){
				tipoB = t2.tipo;
			}
			cad += t2.salida;
			if($tipo!=Simbolo.REAL){
				$tipo = tipoB;
			}
			if(!$error8){
				$error8=t2.error8;
			}
			
		})*{
			if(sucedio){
				if(sA.tipo == Simbolo.REAL && tipoB == Simbolo.ENTERO){
					$salida =  cad+ ")).toDouble())";
				} else {
					$salida = cad+")";
				}
			} else {
				
				$salida = t1.text;
				//$salida = AnalitzadorSintactic.pendiente2 + t1.text;
				//AnalitzadorSintactic.pendiente2 ="";
				$tipo = tipoB;
			}
		};
				
	term[Simbolo sA, int tipoB, boolean primi, boolean sucedido,String opSum ] returns [String salida, int tipo, String text, boolean sucedio, boolean error8]
		@init{
			$salida="";
			String cad = "";
			int tipoaux= $tipoB;
			$sucedio = $sucedido;
			
			
		}:
		f1=factor[sA,tipoB,primi,$opSum]{
			$tipoB = f1.tipo;
			cad += f1.salida;
			$text = f1.text;
			$tipo = f1.tipo;
			tipoaux = f1.tipo;
			$error8 = f1.error8;
			//System.out.println(f1.salida);
		}
		(MULOP{
			if(!$sucedio){
			if(sA.tipo == Simbolo.ENTERO){
				cad = "new Integer("+cad;
			} else {
				cad = "new Double(" + cad;
			}}		
			
			$sucedio = true;
		} f2=factor[sA,tipoaux,false,$MULOP.text]{
			if(tipoaux==Simbolo.ENTERO){
				tipoaux = f2.tipo;
			}
			cad+= f2.salida;
			if($tipo == Simbolo.ENTERO){
				$tipo = f2.tipo;
			}
			if(!$error8){
				$error8 = f2.error8;
			}
			//System.out.println(f2.salida);
		})*{
			cad+= AnalitzadorSintactic.pendiente2;
			
			AnalitzadorSintactic.pendiente2="";
			$salida = cad;
			
		
		};
			
	factor[Simbolo sA, int tipoB, boolean primi,String op] returns [String salida, int tipo,String text, boolean error8, int original]
		@init{
			String cad="";
			Simbolo s= null;
			$salida="";
			$error8=false;
		}:
		REAL{
			cad += AnalitzadorSintactic.traduceOperacion(sA,tipoB,$REAL.text,Simbolo.REAL,false,primi,op);	
			$salida = cad;	
			$tipo = Simbolo.REAL;
			if(sA. tipo == Simbolo.REAL){
				$text = "new Double("+$REAL.text+")";
			} else {
				//ERRORRRRRRRRRRR
				$text = "new Double("+$REAL.text+")";
			}
			
			if(sA.tipo == Simbolo.ENTERO){
				$error8 = true;
			}
			$original = Simbolo.REAL;
		
		}
		|
		ENTERO{
			cad += AnalitzadorSintactic.traduceOperacion(sA,tipoB,$ENTERO.text,Simbolo.ENTERO,false,primi,op);	
			$salida = cad;
			$tipo = Simbolo.ENTERO;
			
			if(sA. tipo == Simbolo.ENTERO){
				$text = "new Integer("+$ENTERO.text+")";
			} else {
				//ERRORRRRRRRRRRR
				$text = "new Double((new Integer("+ $ENTERO.text + ")).toDouble())";
			}
			$original = Simbolo.ENTERO;
			
		
		}
		|
		ID{
			//System.out.println("**" + $ID.text);	
			s=tsimbolos.busca($ID.text);
			
			if(s==null){
				error6($ID.line,$ID.pos,$ID.text);
				
			} else if (!s.esVAR()){
				error7($ID.line,$ID.pos,$ID.text);
			
			}		
			cad += AnalitzadorSintactic.traduceOperacion(sA,tipoB,tsimbolos.obtinNom($ID.text),s.tipo,true,primi,op);
			if(s.tipo == sA.tipo){
				$text = tsimbolos.obtinNom($ID.text);
			} else if(s.tipo == Simbolo.ENTERO){
				$text = "new Double("+tsimbolos.obtinNom($ID.text) + ".toDouble())";
			} 
			if(sA.tipo == Simbolo.ENTERO && s.tipo == Simbolo.REAL){
				$error8 = true;
			}
			
			$tipo = sA.tipo;
			$original = sA.tipo;
			//System.out.println(sA);
			$salida = cad;
	
		}{
			
		};
	



PARI    :'(' {AnalitzadorSintactic.acumulado+= "pari"; AnalitzadorSintactic.pirula++;} ;
PARD    :')' {AnalitzadorSintactic.acumulado+= "pard";AnalitzadorSintactic.pirula++;} ;
MULOP	:('*'|'/'){AnalitzadorSintactic.acumulado+= "mulop";AnalitzadorSintactic.pirula++;};
ADDOP	:('+'|'-'){AnalitzadorSintactic.acumulado+= "addop";AnalitzadorSintactic.pirula++;};
PYC	:';'{AnalitzadorSintactic.acumulado+= "pyc";AnalitzadorSintactic.pirula++;};
ASIG	:'='{AnalitzadorSintactic.acumulado+= "asig";AnalitzadorSintactic.pirula++;};
DOUBLE	: 'double'{AnalitzadorSintactic.acumulado+= "double";AnalitzadorSintactic.pirula++;};
INT	: 'int'{AnalitzadorSintactic.acumulado+= "int";AnalitzadorSintactic.pirula++;};
MAIN	: 'main'{AnalitzadorSintactic.acumulado+= "main";AnalitzadorSintactic.pirula++;};
LLAVEI  :'{' {AnalitzadorSintactic.acumulado+= "llavei";AnalitzadorSintactic.pirula++;};
LLAVED  :'}' {AnalitzadorSintactic.acumulado+= "llaved";AnalitzadorSintactic.pirula++;};
ENTERO 	:'0'..'9'+{AnalitzadorSintactic.acumulado+= "entero";AnalitzadorSintactic.pirula++;};
ID  	:('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*{AnalitzadorSintactic.acumulado+= "id";AnalitzadorSintactic.pirula++;};
REAL    :   ('0'..'9')+ '.' ('0'..'9')* | '.' ('0'..'9')+ | ('0'..'9')+{AnalitzadorSintactic.acumulado+= "real";AnalitzadorSintactic.pirula++;};
NEWLINE          : ('\r'? '\n'|' '|'\t')+  { skip(); };
COMENTARIO       : '/*' .* '*/' {skip();};
